package services;

import domain.entities.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Service
public class CenterCRUDService implements CRUDService<Centro>{

    private CentroDAO dao;
    private ComiteDocenciaDAO comiteDocenciaDAO;
    private CentroAddressDAO centroAddressDAO;
    private TherapeuticAreaDAO therapeuticAreaDAO;
    private SpecialtyDAO specialtyDAO;

    public CenterCRUDService() {
    }

    @Autowired
    public CenterCRUDService(CentroDAO centroDAO, ComiteDocenciaDAO comiteDocenciaDAO,
                             CentroAddressDAO centroAddressDAO, TherapeuticAreaDAO therapeuticAreaDAO, SpecialtyDAO specialtyDAO) {
        this.comiteDocenciaDAO = comiteDocenciaDAO;
        this.centroAddressDAO = centroAddressDAO;
        this.dao = centroDAO;
        this.therapeuticAreaDAO = therapeuticAreaDAO;
        this.specialtyDAO = specialtyDAO;
    }

    @Override
    public <V extends Criteria> List<Centro> list(V criteria) {
        List<Centro> list = dao.findAll();
        Iterator<Centro> it = list.iterator();
        while(it.hasNext()){
            if(!criteria.isIn(it.next())){
                it.remove();
            }
        }
        return list;
    }

    public List<Centro> list(){
        return dao.findAll();
    }

    public void delete(Centro centro){
        dao.delete(centro);
    }

    public Centro findById(int id) {
        return dao.findById(id);
    }

    public void save(Centro centro, List<Address> addresses) {
        if(centro.getInstitucion().isEmpty() || addresses.isEmpty()){
            throw new IllegalArgumentException("Site without institution name or addresses");
        }

        Centro persisted = null;
        if(centro.getId()!=null && centro.getId() != 0){
            persisted = dao.findById(centro.getId());
            for(CentroAddress ca : persisted.getCentroAddresses()){
                centroAddressDAO.delete(ca);
            }
        }

        ArrayList<Address> addressesNull = new ArrayList<Address>(0);

        Iterator<Address> itAddr = addresses.iterator();
        while(itAddr.hasNext()){
            Address actual = itAddr.next();
            if(actual == null || actual.getCity().trim().isEmpty()){
                addressesNull.add(actual);
            }
        }

        addresses.removeAll(addressesNull);

        ArrayList<CentroAddress> centroAddressesNull = new ArrayList<CentroAddress>(0);

        for(CentroAddress ca1 : centro.getCentroAddresses()){
            if(ca1 == null || ca1.getAddress().getAddress().equals("Choose an Address") || ca1.getTherapeuticArea().getId() == -1 || ca1.getSpeciality().getId() == -1)
                centroAddressesNull.add(ca1);
            else if(ca1.getAddress().getCity().equals("undefined")){
                if( (ca1.getTherapeuticArea() == null || ca1.getTherapeuticArea().getId() != -1) && (ca1.getSpeciality() == null || ca1.getSpeciality().getId() == -1)){
                    centroAddressesNull.add(ca1);
                }
                else{
                    ca1.getAddress().setAddress("");
                    ca1.getAddress().setCity("");
                }
            }
        }

        centro.getCentroAddresses().removeAll(centroAddressesNull);

        ArrayList<CentroAddress> aux = new ArrayList<CentroAddress>(0);

        for(Address a : addresses){
            boolean add = true;
            for(CentroAddress c : centro.getCentroAddresses()){
                if(a.getAddress().equals(c.getAddress().getAddress()) &&
                        a.getCity().equals(c.getAddress().getCity()) &&
                        a.getCountry().equals(c.getAddress().getCountry()) &&
                        a.getProvince().equals(c.getAddress().getProvince())){
                    add = false;
                }
            }
            if(add)
                aux.add(new CentroAddress(a, null, null, null));
        }
        centro.getCentroAddresses().addAll(aux);

        centroAddressesNull.clear();

        for(CentroAddress c : centro.getCentroAddresses()){
        boolean exists = false;
            for(Address a : addresses){
                if(a.getAddress().equals(c.getAddress().getAddress()) &&
                        a.getCity().equals(c.getAddress().getCity()) &&
                        a.getCountry().equals(c.getAddress().getCountry()) &&
                        a.getProvince().equals(c.getAddress().getProvince())){
                    c.setAddress(a);
                    exists = true;
                }
            }
            if( (c.getTherapeuticArea() == null || c.getTherapeuticArea().getId() == -1) && c.getSpeciality() == null && !exists){
                centroAddressesNull.add(c);
            }
            else{
                if(c.getTherapeuticArea() != null && c.getTherapeuticArea().getId() != -1)
                    c.setTherapeuticArea(therapeuticAreaDAO.findById(c.getTherapeuticArea().getId()));
                if(c.getSpeciality() != null)
                    c.setSpeciality(specialtyDAO.findById(c.getSpeciality().getId()));
                c.setCentro(centro);
                if(!exists)
                    c.setAddress(null);
            }
        }

        centro.getCentroAddresses().removeAll(centroAddressesNull);
        dao.merge(centro);
    }

    public List<ComiteDocencia> getAllTeachingCommittee(Centro centro){
        List<ComiteDocencia> list = comiteDocenciaDAO.findAll();
        Iterator<ComiteDocencia> it = list.iterator();
        while(it.hasNext()){
            ComiteDocencia cd = it.next();
            if(!(cd.getCentro().getId() == centro.getId())){
                it.remove();
            }
        }
        return list;
    }

    public CentroAddress findCenterAddressById(int id) {
        return centroAddressDAO.findById(id);
    }

    public void deleteCentroAddress(CentroAddress centerAddress) {
        centroAddressDAO.delete(centerAddress);
    }

    public List<Centro> getAllByCountries(List<String> countries){

        List<Centro> list = dao.findAll();
        Iterator<Centro> it = list.iterator();

        while(it.hasNext()){
            Centro c = it.next();

            Iterator<CentroAddress> it2 = c.getCentroAddresses().iterator();
            boolean is = false;
            while (it2.hasNext()){
                CentroAddress ca = it2.next();
                String contry = ca.getAddress().getCountry();
                for(String coun : countries){
                    if( coun.toUpperCase().trim().equals(contry.toUpperCase().trim()) )
                        is = true;
                }
            }
            if(!is){
                it.remove();
            }
        }
        return list;
    }

    public List<Centro> listByInstitution(String institution) {
        Centro c = new Centro();
        c.setInstitucion(institution);
        Criteria cr = new CriteriaByInstitution(c);

        return list(cr);
    }

    public ArrayList<Centro> findByProtocol(ProtocoloCompromisopais protocoloCompromisopais) {

        return null;  //To change body of created methods use File | Settings | File Templates.
    }

    private class CriteriaByInstitution extends Criteria{

        private Centro centro;

        public CriteriaByInstitution(Centro centro) {
            this.centro = centro;
        }

        @Override
        public boolean isIn(Object element){
            boolean isIn = true;

            Centro other = (Centro)element;

             isIn = isSubstring(centro.getInstitucion(),other.getInstitucion());

            return isIn;
        }
    }
}
